#include "FLOAT.h"

FLOAT F_mul_F(FLOAT a, FLOAT b) {
	int sign = (a & 0x80000000) ^ (b & 0x80000000);
	long long la = a, lb = b;
	int result = (la * lb) >> 16;
	result = (result & 0x7fffffff) | sign;
	return result;
	//return (a >> 8) * (b >> 8);
}

FLOAT F_div_F(FLOAT a, FLOAT b) {
	/* Dividing two 64-bit integers needs the support of another library
	 * `libgcc', other than newlib. It is a dirty work to port `libgcc'
	 * to NEMU. In fact, it is unnecessary to perform a "64/64" division
	 * here. A "64/32" division is enough.
	 *
	 * To perform a "64/32" division, you can use the x86 instruction
	 * `div' or `idiv' by inline assembly. We provide a template for you
	 * to prevent you from uncessary details.
	 *
	 *     asm volatile ("??? %2" : "=a"(???), "=d"(???) : "r"(???), "a"(???), "d"(???));
	 *
	 * If you want to use the template above, you should fill the "???"
	 * correctly. For more information, please read the i386 manual for
	 * division instructions, and search the Internet about "inline assembly".
	 * It is OK not to use the template above, but you should figure
	 * out another way to perform the division.
	 */
	int ext = (a < 0 ? 0xffffffff : 0x0);
	int sign = (a & 0x80000000) ^ (b & 0x80000000);
	int result, r, temp;
	/*asm volatile (
			"movl %2, %%edx;"
			"movl %3, %%eax;"
			"movl %4, %%ebx;"
			"idivl %%ebx;"
			:"=a"(result), "=d"(r):"g"(ext),"g"(a),"g"(b));
	*/
	result = a/b;
	r = a%b;
	result <<= 16;
	ext = (r < 0 ? 0xffffffff : 0x0);
	ext = (ext << 16) | ((r >> 16) & 0xffff);
	temp = r << 16;
	asm volatile (
			"movl %1, %%edx;"
			"movl %2, %%eax;"
			"movl %3, %%ebx;"
			"idivl %%ebx;"
			:"=a"(r)
			:"m"(ext), "m"(temp), "m"(b)
			:);
	
	result += r;
	result = (result & 0x7fffffff) | sign;
	return result;
}

FLOAT f2F(float a) {
	/* You should figure out how to convert `a' into FLOAT without
	 * introducing x87 floating point instructions. Else you can
	 * not run this code in NEMU before implementing x87 floating
	 * point instructions, which is contrary to our expectation.
	 *
	 * Hint: The bit representation of `a' is already on the
	 * stack. How do you retrieve it to another variable without
	 * performing arithmetic operations on it directly?
	 */
	union {
		float f;
		struct{
			unsigned int frac : 23;
			unsigned int expn : 8;
			unsigned int sign : 1;
		};
	} data;
	int temp;
	data.f = a;
	temp = (data.expn == 0 ? data.frac : data.frac | 0x00800000);
	if (data.expn - 0x7f > (23 - 16)) {
		temp <<= (data.expn - 0x7f - (23 - 16));
	}
	else {
		temp >>= ((23 - 16) + 0x7f - data.expn);
	}
	temp = (data.sign == 1 ? - temp : temp);
	return temp;
}

FLOAT Fabs(FLOAT a) {
	return (a < 0 ? - a : a);
}

/* Functions below are already implemented */

FLOAT sqrt(FLOAT x) {
	FLOAT dt, t = int2F(2);

	do {
		dt = F_div_int((F_div_F(x, t) - t), 2);
		t += dt;
	} while(Fabs(dt) > f2F(1e-4));

	return t;
}

FLOAT pow(FLOAT x, FLOAT y) {
	/* we only compute x^0.333 */
	FLOAT t2, dt, t = int2F(2);

	do {
		t2 = F_mul_F(t, t);
		dt = (F_div_F(x, t2) - t) / 3;
		t += dt;
	} while(Fabs(dt) > f2F(1e-4));

	return t;
}

